package impl;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import java.util.List;

import api.ejb.*;
import api.ejb.IWallet.MovementsType;


import api.InvalidAuthenticationException;
import api.PhasebookToken;
import api.UserProfileTypes.Gender;
import api.UserProfileTypes.NotificationApproach;

import javax.ejb.EJB;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.jboss.logging.Logger;
import org.jboss.soa.esb.client.ServiceInvoker;
import org.jboss.soa.esb.couriers.FaultMessageException;
import org.jboss.soa.esb.listeners.message.MessageDeliverException;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.format.MessageFactory;

import p3_entities.Friend;
import p3_entities.Lindenmovement;
import p3_entities.Usermessage;
import p3_entities.Userprofile;

import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;

import messageObjects.BalanceObj;
import messageObjects.LotteryGameObj;
import messageObjects.MovementObj;

import org.jboss.soa.esb.message.Body;
import org.jboss.soa.esb.message.format.MessageType;
import org.jboss.soa.esb.services.registry.RegistryException;


/**
 * Session Bean implementation class Facade
 */
@Stateless(name = "IFacade")
@WebService(endpointInterface="api.ejb.IFacade", serviceName="ESBWS")
@Remote(IFacade.class)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class Facade implements IFacade {
	
	@PersistenceContext(unitName = "PhaseBookPU")
	EntityManager em;

	@EJB(beanName = "IAuthenticator")
	IAuthenticator authenticator;

	@EJB(beanName = "ISocializer")
	ISocializer socializer;
	@EJB(beanName = "IUserDataManager")
	IUserDataManager dataManager;	
	@EJB(beanName = "IMessages")
	IMessages messages;
	@EJB(beanName = "IPhotos")
	IPhotos photos;
	
	private static final Logger log = Logger.getLogger(Facade.class);

	boolean authenticated;
	PhasebookToken token;
	
	private static int APP_ID_GAME = 1;
	private static int PRIZE_MULTIPLIER = 10;

	/**
	 * Default constructor.
	 */
	public Facade() {
	}

	
	private void validateAuthentication(PhasebookToken token) throws InvalidAuthenticationException {
		
		if (!authenticated) {

			log.warn("Authentication failed.");
			throw new InvalidAuthenticationException();
		}
		
		if (!authenticator.validateAuthenticationToken(token.getToken())) {
			authenticated = false;
			System.out.println("*** Validation expired ***");
			throw new InvalidAuthenticationException();
		}

	}

	@Override
	public boolean registerUser(String username, String password)
			throws InvalidAuthenticationException {

		try {

			return this.authenticator.registerUser(username, password);

		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	@Override
	public PhasebookToken authenticate(String username, String password)
			throws InvalidAuthenticationException {

		try {

			this.token = this.authenticator.authenticate(username, password);
			this.authenticated = true;

			return  this.token;
			

		} catch (Exception e) {
			e.printStackTrace();
			throw new InvalidAuthenticationException();
		}
	}

	@Override
	public Date getLastLogin(PhasebookToken token, String username)
			throws InvalidAuthenticationException {
		//validateAuthentication();

		try {

			return this.authenticator.getLastLogin(username);
		} catch (Exception e) {
			return null;
		}

	}

	@Override
	public boolean resetPassword(PhasebookToken token, String username)
			throws InvalidAuthenticationException {

		try {
			return this.authenticator.resetPassword(username);

		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public boolean registerBet(PhasebookToken token, int choice, int amount, int gameId)
			throws InvalidAuthenticationException {
		//validateAuthentication();

		try {
			Message message = MessageFactory.getInstance().getMessage();   
			
			message.getBody().add("uid",token.getUserId().intValue());
			message.getBody().add("appId",token.getAppId().intValue());
			message.getBody().add("tokenId",token.getToken());
			
			Map<String, Object> toESBMap = new HashMap<String, Object>();
			toESBMap.put("uid", token.getUserId());
			toESBMap.put("gameId", gameId);
			toESBMap.put("amount", amount);
			toESBMap.put("bet", choice);
			
			message.getBody().add(toESBMap);
			
		
			
			System.out.println("******************** SERVICE INVOKER ************");
			
            ServiceInvoker invoker = new ServiceInvoker("LotteryServices", "RegisterBet");
            invoker.deliverAsync(message);
            
			System.out.println("******************** MESSAGE DELIVERED ************");


			//wallet.debitLinden(uid, amount);
			//lotteryGame.makeBet(APP_ID_GAME, choice, amount, uid, gameId);
			
			return true;
			
		} catch (Exception e) {
			
			e.printStackTrace();
			return false;
		}
	}

	@Override
	public LotteryGameObj getActiveLotteryDetails(PhasebookToken token)
			throws InvalidAuthenticationException {
		//validateAuthentication();

		try {
			//validateAuthentication();

			try {
				
				Message message = MessageFactory.getInstance().getMessage();   
				
				message.getBody().add("uid",token.getUserId().intValue());
				message.getBody().add("appId",token.getAppId().intValue());
				message.getBody().add("tokenId",token.getToken());
				
				
	            ServiceInvoker invoker = new ServiceInvoker("PhaseBookSocializing", "GetActiveLottery");
	            Message response = invoker.deliverSync(message, 10000);
	            
	            
	            
	            // invoker.deliverAsync(message);
	            //Map response = (HashMap) message.getBody().get();
	       
	            Body b = response.getBody();
	            for (String str : b.getNames()) {
	    			System.out.println(str + " = " + b.get(str));
	    		}
	    		
	            messageObjects.LotteryGameObj game = (messageObjects.LotteryGameObj) b.get("lottery");
	            
	            

				
				return game;
				//return lotteryGame.getActiveLottery();


			} catch (Exception e) {
				return null;
			}

		} catch (Exception e) {
			return null;
		}
	}

	@Override
	public List<String> searchFriends(PhasebookToken token, String searchString)
			throws InvalidAuthenticationException {
		//validateAuthentication();

		try {
			return this.socializer.searchFriends(searchString);

		} catch (Exception e) {
			return null;
		}
	}

	@Override
	public boolean sendFriendshipInvitation(PhasebookToken token, int fromId, int toId)
			throws InvalidAuthenticationException {
		//validateAuthentication();

		try {
			
			
			
				Message message = MessageFactory.getInstance().getMessage();   
				
				message.getBody().add("uid",token.getUserId().intValue());
				message.getBody().add("appId",token.getAppId().intValue());
				message.getBody().add("tokenId",token.getToken());
				message.getBody().add("origUserId",fromId);
				message.getBody().add("destUserId",toId);
				
				System.out.println("******************** SERVICE INVOKER ************");
				
	            ServiceInvoker invoker = new ServiceInvoker("PhaseBookSocializing", "SendFriendshipRequest");
	            invoker.deliverAsync(message);
	            
				System.out.println("******************** MESSAGE DELIVERED ************");
				
				return true;
			
			//return this.socializer.sendFriendshipInvitation(fromId, toId);
	
		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public List<Friend> getPendingFriendshipRequests(PhasebookToken token)
			throws InvalidAuthenticationException {
		//validateAuthentication();

		try {
			return this.socializer.getPendingFriendshipRequests(token.getUserId());
		} catch (Exception e) {
			return null;
		}

	}

	@Override
	public boolean confirmFriendshipRequest(PhasebookToken token, int requesterdId)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			
			Message message = MessageFactory.getInstance().getMessage();   
			
			message.getBody().add("uid",token.getUserId().intValue());
			message.getBody().add("appId",token.getAppId().intValue());
			message.getBody().add("tokenId",token.getToken());
			message.getBody().add("requesterId",requesterdId);
			
			System.out.println("******************** SERVICE INVOKER ************");
			
            ServiceInvoker invoker = new ServiceInvoker("PhaseBookSocializing", "SendFriendshipConfirmationRequest");
            invoker.deliverAsync(message);
            
			System.out.println("******************** MESSAGE DELIVERED ************");
			
			return true;
			
		//return this.socializer.sendFriendshipInvitation(fromId, toId);

		} catch (Exception e) {
			return false;
		}

	}

	@Override
	public boolean isFriendWith(PhasebookToken token, int baseId, int friendId)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.socializer.isFriendWith(baseId, friendId);
		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public List<Userprofile> getMyFriends(PhasebookToken token)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.socializer.getMyFriends(token.getUserId());
		} catch (Exception e) {
			return null;
		}
	}

	@Override
	public boolean publishPublicMessage(PhasebookToken token, int ownerId, int posterId,
			String message, int photoId) throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.messages.publishPublicMessage(ownerId, posterId,
					message, photoId);
		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public boolean publishPrivateMessage(PhasebookToken token, int ownerId, int posterId,
			String message, int photoId) throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.messages.publishPrivateMessage(ownerId, posterId,
					message, photoId);
		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public List<Usermessage> getPublicMessageList(PhasebookToken token)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.messages.getPublicMessageList(token.getUserId());
		} catch (Exception e) {
			return null;
		}
	}

	@Override
	public int addPhoto(PhasebookToken token, String photoPath)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.photos.addPhoto(token.getUserId(), photoPath);
		} catch (Exception e) {
			return -1;
		}
	}

	@Override
	public List<Usermessage> getPrivateMessageList(PhasebookToken token)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.messages.getPrivateMessageList(token.getUserId());
		} catch (Exception e) {
			return null;
		}
	}

	@Override
	public boolean updateName(PhasebookToken token, String name)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.dataManager.updateName(token.getUserId(), name);
		} catch (Exception e) {
			return false;
		}		
	}

	@Override
	public boolean updateAge(PhasebookToken token, int age)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.dataManager.updateAge(token.getUserId(), age);
		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public boolean updateCity(PhasebookToken token, String city)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.dataManager.updateCity(token.getUserId(), city);
		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public boolean updateGender(PhasebookToken token, Gender sex)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.dataManager.updateGender(token.getUserId(), sex);
		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public boolean updateEmail(PhasebookToken token, String email)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.dataManager.updateEmail(token.getUserId(), email);
		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public boolean updateNotificationApproach(PhasebookToken token,
			NotificationApproach approach, boolean flag)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.dataManager.updateNotificationApproach(token.getUserId(), approach,
					flag);
		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public boolean updatePhoto(PhasebookToken token, int photoId)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.dataManager.updatePhoto(token.getUserId(), photoId);
		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public Userprofile getProfileById(PhasebookToken token)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.dataManager.getProfileById(token.getUserId());
		} catch (Exception e) {
			return null;
		}
	}

	@Override
	public Userprofile getProfileByUsername(PhasebookToken token, String username)
			throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.dataManager.getProfileByUsername(username);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	

	@Override
	public Userprofile getLoggedProfile(PhasebookToken token) throws InvalidAuthenticationException {
		//validateAuthentication();
		try {
			return this.getProfileById(token);
		} catch (Exception e) {
			return null;
		}
	}

	

	@Override
	public boolean reloadLinden(PhasebookToken token, int amount, MovementsType type) {
		/*
		return wallet.reloadLinden(token.getUserId(), amount, type);
		*/
		
		try {
			//validateAuthentication();

			try {
				
				Message message = MessageFactory.getInstance().getMessage();   
				
				message.getBody().add("uid",token.getUserId().intValue());
				message.getBody().add("appId",token.getAppId().intValue());
				message.getBody().add("tokenId",token.getToken());
				//message.getBody().add("amount",amount);
				//message.getBody().add("type",type);
				
				HashMap map = new HashMap();
				map.put("uid", token.getUserId().intValue());
				map.put("amount", amount);
				map.put("type", type.name());
				
				message.getBody().add(map);
				
				System.out.println("******************** Amount: "+amount+" type:"+type.name());
				
				System.out.println("******************** SERVICE INVOKER ************");
				
	            ServiceInvoker invoker = new ServiceInvoker("BankServices", "MakeCreditMovementService");
	            Message response = invoker.deliverSync(message, 10000);
				
				return true;
				//return lotteryGame.getActiveLottery();


			} catch (Exception e) {
				return false;
			}

		} catch (Exception e) {
			return false;
		}
	}

	

	

	

	@Override
	public BalanceObj getUserBalance(PhasebookToken token) {

			Message message = MessageFactory.getInstance().getMessage();   
			
			message.getBody().add("uid",token.getUserId().intValue());
			message.getBody().add("appId",token.getAppId().intValue());
			message.getBody().add("tokenId",token.getToken());
			
			System.out.println("******************** SERVICE INVOKER ************");
			
            ServiceInvoker invoker;
			try {
				invoker = new ServiceInvoker("PhaseBookSocializing", "GetUserBalance");
	            Message response = invoker.deliverSync(message, 30000);
	            
	            // invoker.deliverAsync(message);
	            //Map response = (HashMap) message.getBody().get();
	       
	            Body b = response.getBody();
	            for (String str : b.getNames()) {
	    			System.out.println(str + " = " + b.get(str));
	    		}
	    		
	            messageObjects.BalanceObj balance = (messageObjects.BalanceObj) b.get("balance");
	            
				System.out.println("----------RECEIVED BALANCE: "+balance.getBalance()+"::"+balance.getMovements().size());

	            for(MovementObj m : balance.getMovements()) {
	            	
	    			System.out.println("AMOUT: "+m.getAmount()+"::DATE "+m.getDate()+"::"+m.getDescription());

	            }
	            
				System.out.println("******************** MESSAGE DELIVERED ************");
		
//				return wallet.getUserBalance(uid);
				return balance;
		
			
			//return this.socializer.sendFriendshipInvitation(fromId, toId);

			} catch (MessageDeliverException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			} catch (FaultMessageException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;

			} catch (RegistryException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;

			}
            
            
            
           

	}

	@Override
	public String getEMailById(PhasebookToken token) throws InvalidAuthenticationException {
		return this.getProfileById(token).getEmail();
	}

	@Override
	public boolean validateAuthenticationToken(PhasebookToken token)
			throws InvalidAuthenticationException {
		// TODO Auto-generated method stub
		return false;
	}

}
